home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fsrmt / fsrmtIO.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  42.8 KB  |  1,359 lines

  1. /* 
  2.  * fsSpriteIO.c --
  3.  *
  4.  *    This has the stubs for remote I/O operations handled by Sprite servers.
  5.  *
  6.  * Copyright (C) 1987 Regents of the University of California
  7.  * All rights reserved.
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fsrmt/fsrmtIO.c,v 9.22 92/08/10 17:36:45 mgbaker Exp $ SPRITE (Berkeley)";
  19. #endif not lint
  20.  
  21. #include <sprite.h>
  22. #include <fs.h>
  23. #include <fsutil.h>
  24. #include <fsio.h>
  25. #include <fsrmtInt.h>
  26. #include <fsNameOps.h>
  27. #include <fsprefix.h>
  28. #include <fscache.h>
  29. #include <fsconsist.h>
  30. #include <fsioFile.h>
  31. #include <fsStat.h>
  32. #include <proc.h>
  33. #include <rpc.h>
  34. #include <vm.h>
  35. #include <dbg.h>
  36. #include <fsrecov.h>
  37. #include <recov.h>
  38.  
  39. int FsrmtRpcCacheUnlockBlock _ARGS_((ClientData clientData));
  40.  
  41. Boolean fsrmt_RpcDebug = FALSE;
  42.  
  43.  
  44. /*
  45.  *----------------------------------------------------------------------
  46.  *
  47.  * Fsrmt_Read --
  48.  *
  49.  *    Read data from a remote file/device/pipe/etc.
  50.  *    This routine is in charge of breaking the request up into pieces
  51.  *    that can be handled by the RPC system.
  52.  *    Also, if the FS_USER flag is present then this will allocate
  53.  *    a temporary buffer in the kernel to avoid addressing problems
  54.  *    in the RPC interrupt handler.
  55.  *
  56.  * Results:
  57.  *    SUCCESS.
  58.  *
  59.  * Side effects:
  60.  *    The buffer is filled with the number of bytes indicated by
  61.  *    the bufSize parameter.  *readCountPtr is filled with the number
  62.  *    of bytes actually read.
  63.  *
  64.  *----------------------------------------------------------------------
  65.  */
  66. ReturnStatus
  67. Fsrmt_Read(streamPtr, readPtr, waitPtr, replyPtr)
  68.     Fs_Stream    *streamPtr;        /* Stream to Remote I/O handle. */
  69.     Fs_IOParam        *readPtr;    /* Read parameter block. */
  70.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  71.     Fs_IOReply        *replyPtr;    /* Signal to return, if any,
  72.                      * plus the amount read. */
  73. {
  74.     register Fsrmt_IOHandle *rmtHandlePtr =
  75.         (Fsrmt_IOHandle *)streamPtr->ioHandlePtr;
  76.     ReturnStatus     status;
  77.     Rpc_Storage     storage;
  78.     FsrmtIOParam    readParams;
  79.     register Boolean    userSpace;
  80.     int            amountRead;
  81.     register Address    readBufferPtr = (Address)NIL;
  82.  
  83.     status = SUCCESS;
  84.     /*
  85.      * Set up parameters that won't change in each loop iteration.
  86.      */
  87.     readParams.fileID = rmtHandlePtr->hdr.fileID;
  88.     readParams.streamID = streamPtr->hdr.fileID;
  89.     if (waitPtr == (Sync_RemoteWaiter *)NIL) {
  90.     readParams.waiter.hostID = -1;
  91.     readParams.waiter.pid = -1;
  92.     } else {
  93.     readParams.waiter = *waitPtr;
  94.     }
  95.     readParams.io.buffer = 0;    /* not used */
  96.     userSpace = readPtr->flags & FS_USER;
  97.     readParams.io.flags = readPtr->flags & ~FS_USER;
  98.     readParams.io.procID = readPtr->procID;
  99.     readParams.io.familyID = readPtr->familyID;
  100.     readParams.io.uid = readPtr->uid;
  101.     readParams.io.reserved = 0;
  102.  
  103.     storage.requestParamPtr = (Address)&readParams;
  104.     storage.requestParamSize = sizeof(readParams);
  105.     storage.requestDataPtr = (Address)NIL;
  106.     storage.requestDataSize = 0;
  107.  
  108.     /*
  109.      * Allow remote site to return a signal.
  110.      */
  111.     storage.replyParamPtr = (Address)replyPtr;
  112.     storage.replyParamSize = sizeof(Fs_IOReply);
  113.  
  114.     if (userSpace) {
  115.     /*
  116.      * We suffer a malloc and copy cost here because we don't
  117.      * map the users buffer into the kernel and we can't rely
  118.      * on being able to address the user's context from the
  119.      * interrupt handler that receives the packet.
  120.      */
  121.     readBufferPtr =  (Address)malloc((readPtr->length > fsMaxRpcDataSize) ?
  122.                     fsMaxRpcDataSize : readPtr->length);
  123.     }
  124.     /*
  125.      * Outer loop to chop reads into the largest pieces
  126.      * supported by the RPC system.
  127.      */
  128.     amountRead = 0;
  129.     while (readPtr->length > 0) {
  130.     readParams.io.length = (readPtr->length > fsMaxRpcDataSize) ?
  131.                 fsMaxRpcDataSize : readPtr->length;
  132.     readParams.io.offset = readPtr->offset + amountRead;
  133.     if (!userSpace) {
  134.         readBufferPtr = readPtr->buffer + amountRead;
  135.     }
  136.     storage.replyDataSize = readParams.io.length;
  137.     storage.replyDataPtr = readBufferPtr;
  138.  
  139.     status = Rpc_Call(rmtHandlePtr->hdr.fileID.serverID, RPC_FS_READ,
  140.                 &storage);
  141.  
  142.     if (status == SUCCESS || status == FS_WOULD_BLOCK) {
  143.         if (userSpace) {
  144.         if (Vm_CopyOut(storage.replyDataSize, readBufferPtr,
  145.                 readPtr->buffer + amountRead)
  146.                 != SUCCESS) {
  147.             status = FS_INVALID_ARG;
  148.             break;
  149.         }
  150.         }
  151.         readPtr->length -= storage.replyDataSize;
  152.         amountRead += storage.replyDataSize;
  153.         if (storage.replyDataSize < readParams.io.length ||
  154.         status == FS_WOULD_BLOCK) {
  155.         /*
  156.          * Quit on short read because may have hit eof or
  157.          * used up the data in a pipe or device.
  158.          */
  159.         break;
  160.         }
  161.     } else if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  162.         status == RPC_SERVICE_DISABLED) {
  163.         Fsutil_WantRecovery((Fs_HandleHeader *)rmtHandlePtr);
  164.         break;
  165.     } else {
  166.         break;
  167.     }
  168.     }
  169.     replyPtr->length = amountRead;
  170.     Fs_StatAdd(amountRead, fs_Stats.gen.remoteBytesRead,
  171.            fs_Stats.gen.remoteReadOverflow);
  172.     if (userSpace) {
  173.     free(readBufferPtr);
  174.     }
  175.     return(status);
  176. }
  177.  
  178. /*
  179.  *----------------------------------------------------------------------
  180.  *
  181.  * Fsrmt_RpcRead --
  182.  *
  183.  *    Service stub for the RPC_FS_READ call.  This verifies the client
  184.  *    and uses the stream read routine to get data.
  185.  *    There is also an optimization here to read directly
  186.  *    out of the cache for block-aligned cacheable reads.
  187.  *
  188.  * Results:
  189.  *    A return status.
  190.  *
  191.  * Side effects:
  192.  *      If the read would block (ie, no data ready), the remote caller is
  193.  *      put into the file handle's readWaitList.  If the read went ok
  194.  *    a reply message is returned to the caller.  Note that we may
  195.  *    or may not return an Fs_IOReply.  This is not done with a cache
  196.  *    read because signals are not generated in that case, which is
  197.  *    why the Fs_IOReply struct is used.
  198.  *
  199.  *----------------------------------------------------------------------
  200.  */
  201. /*ARGSUSED*/
  202. ReturnStatus
  203. Fsrmt_RpcRead(srvToken, clientID, command, storagePtr)
  204.     ClientData        srvToken;    /* Handle for the server process */
  205.     int            clientID;    /* Sprite ID of client host */
  206.     int            command;    /* IGNORED */
  207.     register Rpc_Storage *storagePtr;    /* Specifies the size and location of
  208.                      * the two parts of the read request.
  209.                      * This routine sets up parts that
  210.                      * indicate the size and location of
  211.                      * the read reply. */
  212. {
  213.     register FsrmtIOParam    *paramsPtr;
  214.     register Fs_HandleHeader    *hdrPtr;
  215.     register Fs_Stream        *streamPtr;
  216.     ReturnStatus    status;
  217.     Rpc_ReplyMem    *replyMemPtr;    /* For call-back to free buffer */
  218.     int            (*callBack) _ARGS_((ClientData));
  219.                 /* Call back to clean up after RPC */
  220.     ClientData        clientData;    /* Client data for callBack */
  221.     FsioStreamClient    *clientPtr;
  222.     Fsrecov_HandleState    recovInfo;
  223.  
  224.     callBack = (int(*)()) NIL;
  225.     clientData = (ClientData) NIL;
  226.  
  227.     paramsPtr = (FsrmtIOParam *)storagePtr->requestParamPtr;
  228.  
  229.     /*
  230.      * Fetch the handle for the file and verify the client.
  231.      */
  232.     hdrPtr = (*fsio_StreamOpTable[paramsPtr->fileID.type].clientVerify)
  233.         (¶msPtr->fileID, clientID, (int *)NIL);
  234.     if (hdrPtr == (Fs_HandleHeader *) NIL) {
  235.     printf("Fsrmt_RpcRead, no handle <%d,%d> client %d\n",
  236.         paramsPtr->fileID.major, paramsPtr->fileID.minor, clientID);
  237.     return(FS_STALE_HANDLE);
  238.     }
  239.     Fsutil_HandleUnlock(hdrPtr);
  240.  
  241.     /*
  242.      * Fetch the shadow stream in case we need to use our offset.
  243.      */
  244.     if (paramsPtr->streamID.type == FSIO_STREAM &&
  245.     paramsPtr->streamID.serverID == rpc_SpriteID) {
  246.     streamPtr = Fsio_StreamClientVerify(¶msPtr->streamID, hdrPtr,
  247.             clientID);
  248.     if (streamPtr == (Fs_Stream *)NIL) {
  249.         printf("Fsrmt_RpcRead no stream <%d> to handle <%d,%d> client %d\n",
  250.             paramsPtr->streamID.minor,
  251.             paramsPtr->fileID.major, paramsPtr->fileID.minor,
  252.             clientID);
  253.         Fsutil_HandleRelease(hdrPtr, FALSE);
  254.         return( (paramsPtr->streamID.minor < 0) ? GEN_INVALID_ARG
  255.                             : FS_STALE_HANDLE );
  256.     } else {
  257.         if (paramsPtr->io.flags & FS_RMT_SHARED) {
  258.         paramsPtr->io.offset = streamPtr->offset;
  259.         }
  260.         Fsutil_HandleUnlock(streamPtr);
  261.     }
  262.     } else {
  263.     /*
  264.      * Read from the cache, no stream available.
  265.      */
  266.     streamPtr = (Fs_Stream *)NIL;
  267.     }
  268.  
  269.     if (hdrPtr->fileID.type == FSIO_LCL_FILE_STREAM &&
  270.     paramsPtr->io.length == FS_BLOCK_SIZE &&
  271.     (paramsPtr->io.offset & FS_BLOCK_OFFSET_MASK) == 0) {
  272.     /*
  273.      * This is a quick check to see if we can go to the cache
  274.      * directly.  This doesn't fit easily into the
  275.      * Stream read interface so it is left as a wart here instead of
  276.      * permeating the whole interface.
  277.      */
  278.     Fscache_Block    *cacheBlockPtr;    /* Direct reference to cache block */
  279.     Fsio_FileIOHandle *handlePtr = (Fsio_FileIOHandle *)hdrPtr;
  280.     int lengthRead = 0;
  281.     status = Fscache_BlockRead(&handlePtr->cacheInfo,
  282.                   paramsPtr->io.offset / FS_BLOCK_SIZE,
  283.                   &cacheBlockPtr, &lengthRead, 
  284.                   FSCACHE_DATA_BLOCK, FALSE);
  285.     if (cacheBlockPtr != (Fscache_Block *)NIL) {
  286.         storagePtr->replyDataPtr = cacheBlockPtr->blockAddr;
  287.         storagePtr->replyDataSize = lengthRead;
  288.         callBack = FsrmtRpcCacheUnlockBlock;
  289.         clientData = (ClientData)cacheBlockPtr;
  290.     } else {
  291.         /*
  292.          * Either we are past eof or there was an I/O error.
  293.          * No data to return.
  294.          */
  295.         callBack = (int(*)())NIL;
  296.         clientData = (ClientData)NIL;
  297.     }
  298.     if (streamPtr != (Fs_Stream *)NIL) {
  299.         streamPtr->offset = paramsPtr->io.offset + lengthRead;
  300.         /*
  301.          * Update shared offset for stream in recov box, for each
  302.          * client's copy, if it's there.
  303.          */
  304.         if (recov_Transparent && streamPtr->flags & FS_RMT_SHARED) {
  305.         LIST_FORALL(&streamPtr->clientList, (List_Links *) clientPtr) {
  306.             if (fsrecov_DebugLevel >= 2) {
  307.             printf("Fsrmt_RpcRead: attempting to update shared ");
  308.             printf("offset for stream %d.%d.%d.%d, client %d\n",
  309.                 paramsPtr->streamID.type,
  310.                 paramsPtr->streamID.serverID,
  311.                 paramsPtr->streamID.major,
  312.                 paramsPtr->streamID.minor, clientPtr->clientID);
  313.             }
  314.             if (Fsrecov_GetHandle(paramsPtr->streamID,
  315.                 clientPtr->clientID,
  316.                 &recovInfo, FALSE) == SUCCESS) {
  317.             recovInfo.clientData = streamPtr->offset;
  318.             if (Fsrecov_UpdateHandle(paramsPtr->streamID,
  319.                 clientPtr->clientID, &recovInfo) != SUCCESS) {
  320.                 panic(
  321.             "Fsrmt_RpcRead: couldn't update recov shared offset");
  322.             }
  323.             }
  324.         }
  325.         }
  326.         Fsutil_HandleLock(streamPtr);
  327.         Fsutil_HandleRelease(streamPtr, TRUE);
  328.     }
  329.     } else {
  330.     /*
  331.      * Regular read to a file, device, pipe, pseudo-device.
  332.      */
  333.     Fs_IOReply *replyPtr = mnew(Fs_IOReply);
  334.  
  335.     replyPtr->length = 0;
  336.     replyPtr->signal = 0;
  337.     replyPtr->flags = 0;
  338.     paramsPtr->io.buffer = (Address) malloc(paramsPtr->io.length);
  339.  
  340.     if (streamPtr == (Fs_Stream *)NIL) {
  341.         printf("Fsrmt_RpcRead, non block-aligned cache read from client %d\n",
  342.         clientID);
  343.         status = GEN_INVALID_ARG;
  344.     } else {
  345.         status = (fsio_StreamOpTable[hdrPtr->fileID.type].read)(streamPtr,
  346.                 ¶msPtr->io, ¶msPtr->waiter, replyPtr);
  347.         streamPtr->offset = paramsPtr->io.offset + replyPtr->length;
  348.         /*
  349.          * Update shared offset for stream in recov box, for each
  350.          * client's copy, if it's there.
  351.          */
  352.         if (recov_Transparent && streamPtr->flags & FS_RMT_SHARED) {
  353.         LIST_FORALL(&streamPtr->clientList, (List_Links *) clientPtr) {
  354.             if (fsrecov_DebugLevel >= 2) {
  355.             printf("Fsrmt_RpcRead: attempting to update shared ");
  356.             printf("offset for stream %d.%d.%d.%d, client %d\n",
  357.                 paramsPtr->streamID.type,
  358.                 paramsPtr->streamID.serverID,
  359.                 paramsPtr->streamID.major,
  360.                 paramsPtr->streamID.minor, clientPtr->clientID);
  361.             }
  362.             if (Fsrecov_GetHandle(paramsPtr->streamID,
  363.                 clientPtr->clientID,
  364.                 &recovInfo, FALSE) == SUCCESS) {
  365.             recovInfo.clientData = streamPtr->offset;
  366.             if (Fsrecov_UpdateHandle(paramsPtr->streamID,
  367.                 clientPtr->clientID, &recovInfo) != SUCCESS) {
  368.                 panic(
  369.             "Fsrmt_RpcRead: couldn't update recov shared offset");
  370.             }
  371.             }
  372.         }
  373.         }
  374.         Fsutil_HandleLock(streamPtr);
  375.         Fsutil_HandleRelease(streamPtr, TRUE);
  376.     }
  377.  
  378.     if (status == SUCCESS || status == FS_WOULD_BLOCK) {
  379.         storagePtr->replyDataPtr = paramsPtr->io.buffer;
  380.         storagePtr->replyDataSize = replyPtr->length;
  381.         storagePtr->replyParamPtr = (Address)replyPtr;
  382.         storagePtr->replyParamSize = sizeof(Fs_IOReply);
  383.         replyMemPtr = (Rpc_ReplyMem *) malloc(sizeof(Rpc_ReplyMem));
  384.         replyMemPtr->paramPtr = storagePtr->replyParamPtr;
  385.         replyMemPtr->dataPtr = storagePtr->replyDataPtr;
  386.         callBack = Rpc_FreeMem;
  387.         clientData = (ClientData)replyMemPtr;
  388.     } else {
  389.         free(paramsPtr->io.buffer);
  390.         free((Address)replyPtr);
  391.     }
  392.     }
  393.     Fsutil_HandleRelease(hdrPtr, FALSE);
  394.     FSRMT_RPC_DEBUG_PRINT1("Fsrmt_RpcRead: Returning %x\n", status);
  395.     if (status == SUCCESS || status == FS_WOULD_BLOCK) {
  396.     Rpc_Reply(srvToken, status, storagePtr, callBack, clientData);
  397.     return(SUCCESS);
  398.     } else {
  399.     return(status);
  400.     }
  401. }
  402.  
  403. /*
  404.  *----------------------------------------------------------------------
  405.  *
  406.  * FsrmtRpcCacheUnlockBlock --
  407.  *
  408.  *    A call-back to release a cache block after a successful read RPC.
  409.  *
  410.  * Results:
  411.  *    None.
  412.  *
  413.  * Side effects:
  414.  *    Unlock the cache block locked down during a read for a remote client.
  415.  *
  416.  *----------------------------------------------------------------------
  417.  */
  418. int
  419. FsrmtRpcCacheUnlockBlock(clientData)
  420.     ClientData clientData;
  421. {
  422.     Fscache_Block *cacheBlockPtr = (Fscache_Block *) clientData;
  423.     Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  424.     return 0;
  425. }
  426.  
  427.  
  428.  
  429. /*----------------------------------------------------------------------
  430.  *
  431.  * Fsrmt_Write --
  432.  *
  433.  *      Write to a remote Sprite file, device, or pipe.  This is in charge
  434.  *    of breaking the write up into pieces that the RPC system can handle.
  435.  *
  436.  * Results:
  437.  *    A return status.
  438.  *
  439.  * Side effects:
  440.  *    The write to the remote file.
  441.  *
  442.  *----------------------------------------------------------------------
  443.  */
  444.  
  445. ReturnStatus
  446. Fsrmt_Write(streamPtr, writePtr, waitPtr, replyPtr)
  447.     Fs_Stream        *streamPtr;    /* Open stream to a remote thing */
  448.     Fs_IOParam        *writePtr;    /* Read parameter block */
  449.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  450.     Fs_IOReply        *replyPtr;    /* Signal to return, if any */
  451. {
  452.     register Fsrmt_IOHandle *rmtHandlePtr =
  453.         (Fsrmt_IOHandle *)streamPtr->ioHandlePtr;
  454.     ReturnStatus     status = SUCCESS;
  455.     Rpc_Storage     storage;
  456.     FsrmtIOParam    writeParams;
  457.     int            amountWritten;    /* Total amount written */
  458.     register int    writeLen;    /* Amount to write each RPC */
  459.     register Boolean    userSpace = writePtr->flags & FS_USER;
  460.     register Address    writeBufferPtr = (Address) NIL;
  461.  
  462.     /*
  463.      * Initialize things that won't change on each RPC.
  464.      */
  465.     writeParams.fileID = rmtHandlePtr->hdr.fileID;
  466.     writeParams.streamID = streamPtr->hdr.fileID;
  467.     if (waitPtr == (Sync_RemoteWaiter *)NIL) {
  468.     writeParams.waiter.hostID = -1;
  469.     writeParams.waiter.pid = -1;
  470.     } else {
  471.     writeParams.waiter = *waitPtr;
  472.     }
  473.  
  474.     writeParams.io.buffer = 0;    /* not used */
  475.     writeParams.io.flags = writePtr->flags & ~FS_USER;
  476.     writeParams.io.procID = writePtr->procID;
  477.     writeParams.io.familyID = writePtr->familyID;
  478.     writeParams.io.uid = writePtr->uid;
  479.     writeParams.io.reserved = 0;
  480.  
  481.     storage.requestParamPtr = (Address)&writeParams;
  482.     storage.requestParamSize = sizeof(writeParams);
  483.     storage.replyParamPtr = (Address) replyPtr;
  484.     storage.replyParamSize = sizeof(Fs_IOReply);
  485.     storage.replyDataPtr = (Address)NIL;
  486.     storage.replyDataSize = 0;
  487.  
  488.     if (userSpace) {
  489.     /*
  490.      * We suffer a malloc and copy cost here because we don't
  491.      * map the users buffer into the kernel and we can't rely
  492.      * on being able to address the users context from the
  493.      * interrupt handler that receives the packet.
  494.      */
  495.     writeBufferPtr = (Address)malloc((writePtr->length > fsMaxRpcDataSize) ?
  496.                      fsMaxRpcDataSize : writePtr->length);
  497.     }
  498.     /*
  499.      * Outer loop to chop reads into the largest pieces
  500.      * supported by the RPC system.
  501.      */
  502.     amountWritten = 0;
  503.     while (writePtr->length > 0) {
  504.     writeLen = (writePtr->length > fsMaxRpcDataSize) ?
  505.             fsMaxRpcDataSize : writePtr->length;
  506.     if (userSpace) {
  507.         if (Vm_CopyIn(writeLen, writePtr->buffer + amountWritten,
  508.             writeBufferPtr) != SUCCESS) {
  509.         status = FS_INVALID_ARG;
  510.         break;
  511.         }
  512.     } else {
  513.         writeBufferPtr = writePtr->buffer + amountWritten;
  514.     }
  515.     storage.requestDataPtr = writeBufferPtr;
  516.     storage.requestDataSize = writeLen;
  517.     writeParams.io.offset = writePtr->offset + amountWritten;
  518.     writeParams.io.length = writeLen;
  519.     
  520.     status = Rpc_Call(rmtHandlePtr->hdr.fileID.serverID, RPC_FS_WRITE,
  521.             &storage);
  522.     if (status == SUCCESS || status == FS_WOULD_BLOCK) {
  523.         writePtr->length -= replyPtr->length;
  524.         amountWritten += replyPtr->length;
  525.         if (status == FS_WOULD_BLOCK || replyPtr->length < writeLen) {
  526.         break;
  527.         }
  528.     } else if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  529.         status == RPC_SERVICE_DISABLED) {
  530.         Fsutil_WantRecovery((Fs_HandleHeader *)rmtHandlePtr);
  531.         break;
  532.     } else {
  533.         break;
  534.     }
  535.     }
  536.     replyPtr->length = amountWritten;
  537.     Fs_StatAdd(amountWritten, fs_Stats.gen.remoteBytesWritten,
  538.            fs_Stats.gen.remoteWriteOverflow);
  539.     if (userSpace) {
  540.     free(writeBufferPtr);
  541.     }
  542.     return(status);
  543. }
  544.  
  545. /*
  546.  *----------------------------------------------------------------------
  547.  *
  548.  * Fsrmt_RpcWrite --
  549.  *
  550.  *    Server stub for the FS_RPC_WRITE call.  This verifies the client
  551.  *    and then calls the stream-type write routine.
  552.  *
  553.  * Results:
  554.  *    If this procedure returns SUCCESS then a reply has been sent to the
  555.  *    client.  If the arguments are bad then FS_STALE_HANDLE is returned
  556.  *    and the main level sends back an error reply.
  557.  *
  558.  * Side effects:
  559.  *    The write on the stream.  See also the stream write routines.
  560.  *
  561.  *----------------------------------------------------------------------
  562.  */
  563. /*ARGSUSED*/
  564. ReturnStatus
  565. Fsrmt_RpcWrite(srvToken, clientID, command, storagePtr)
  566.     ClientData          srvToken;    /* Handle on server process passed to
  567.                      * Rpc_Reply */
  568.     int          clientID;    /* Sprite ID of client host */
  569.     int          command;    /* IGNORED */
  570.     register Rpc_Storage *storagePtr;    /* The request fields refer to the 
  571.                      * request buffers and also indicate 
  572.                      * the exact amount of data in the 
  573.                      * request buffers.  The reply fields 
  574.                      * are initialized to NIL for the
  575.                       * pointers and 0 for the lengths.  
  576.                      * This can be passed to Rpc_Reply */
  577. {
  578.     register Fs_HandleHeader     *hdrPtr;
  579.     register FsrmtIOParam    *paramsPtr;
  580.     register Fs_Stream        *streamPtr;
  581.     Fs_Stream            dummyStream;
  582.     Fs_IOReply            *replyPtr;
  583.     ReturnStatus         status;
  584.     Rpc_ReplyMem        *replyMemPtr;
  585.  
  586.     paramsPtr = (FsrmtIOParam *) storagePtr->requestParamPtr;
  587.  
  588.     hdrPtr = (*fsio_StreamOpTable[paramsPtr->fileID.type].clientVerify)
  589.         (¶msPtr->fileID, clientID, (int *)NIL);
  590.     if (hdrPtr == (Fs_HandleHeader *) NIL) {
  591.     printf( "Fsrmt_RpcWrite, stale handle <%d,%d> client %d\n",
  592.         paramsPtr->fileID.major, paramsPtr->fileID.minor, clientID);
  593.     return(FS_STALE_HANDLE);
  594.     }
  595.     Fsutil_HandleUnlock(hdrPtr);
  596.  
  597.     replyPtr = mnew(Fs_IOReply);
  598.     replyPtr->length = 0;
  599.     replyPtr->flags = 0;
  600.     replyPtr->signal = 0;
  601.  
  602.     paramsPtr->io.flags &= ~FS_USER;
  603.     if (paramsPtr->io.flags & FS_CLIENT_CACHE_WRITE) {
  604.     dummyStream.ioHandlePtr = hdrPtr;
  605.     streamPtr = &dummyStream;
  606.     } else {
  607.     streamPtr = Fsio_StreamClientVerify(¶msPtr->streamID, hdrPtr,
  608.             clientID);
  609.     if (streamPtr == (Fs_Stream *)NIL) {
  610.         printf("Fsrmt_RpcWrite no stream <%d> to handle <%d,%d> client %d\n",
  611.             paramsPtr->streamID.minor,
  612.             paramsPtr->fileID.major, paramsPtr->fileID.minor,
  613.             clientID);
  614.         status = (paramsPtr->streamID.minor < 0) ? GEN_INVALID_ARG
  615.                              : FS_STALE_HANDLE;
  616.         goto exit;
  617.     } else {
  618.         if (paramsPtr->io.flags & FS_RMT_SHARED) {
  619.         paramsPtr->io.offset = streamPtr->offset;
  620.         }
  621.         Fsutil_HandleUnlock(streamPtr);
  622.     }
  623.     }
  624.     paramsPtr->io.buffer = storagePtr->requestDataPtr;
  625.     status = (fsio_StreamOpTable[hdrPtr->fileID.type].write)(streamPtr,
  626.         ¶msPtr->io, ¶msPtr->waiter, replyPtr);
  627.     if (streamPtr != &dummyStream) {
  628.     streamPtr->offset = paramsPtr->io.offset + replyPtr->length;
  629.     Fsutil_HandleLock(streamPtr);
  630.     Fsutil_HandleRelease(streamPtr, TRUE);
  631.     }
  632.     if (status == SUCCESS && (paramsPtr->io.flags & FS_LAST_DIRTY_BLOCK)) {
  633.         /*
  634.          * This is done here because the regular file write routine doesn't
  635.          * know what client is doing the write.
  636.          */
  637.         if (hdrPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  638.             printf("Fsrmt_RpcWrite, lastDirtyBlock flag on bad stream type (%d)\
  639. n",
  640.                     hdrPtr->fileID.type);
  641.         } else {
  642.             Fsio_FileIOHandle *handlePtr = (Fsio_FileIOHandle *)hdrPtr;
  643.             Fsconsist_DeleteLastWriter(&handlePtr->consist, clientID);
  644.     }
  645.     }
  646. exit:
  647.     Fsutil_HandleRelease(hdrPtr, FALSE);
  648.  
  649.     storagePtr->replyParamPtr = (Address)replyPtr;
  650.     storagePtr->replyParamSize = sizeof(Fs_IOReply);
  651.     replyMemPtr = (Rpc_ReplyMem *) malloc(sizeof(Rpc_ReplyMem));
  652.     replyMemPtr->paramPtr = storagePtr->replyParamPtr;
  653.     replyMemPtr->dataPtr = (Address) NIL;
  654.     Rpc_Reply(srvToken, status, storagePtr, Rpc_FreeMem,
  655.         (ClientData)replyMemPtr);
  656.  
  657.     return(SUCCESS);
  658. }
  659.  
  660. /*
  661.  * Parameters for the file select RPC.
  662.  */
  663.  
  664. typedef struct FsRemoteSelectParams {
  665.     Fs_FileID    fileID;        /* File to be re-opened */
  666.     int        read;        /* 1 or zero */
  667.     int        write;        /* 1 or zero */
  668.     int        except;        /* 1 or zero */
  669.     Sync_RemoteWaiter waiter;    /* Process info for remote waiting */
  670. } FsRemoteSelectParams;
  671.  
  672. typedef struct FsRemoteSelectResults {
  673.     int        read;        /* 1 or zero */
  674.     int        write;        /* 1 or zero */
  675.     int        except;        /* 1 or zero */
  676. } FsRemoteSelectResults;
  677.  
  678. /*
  679.  *----------------------------------------------------------------------
  680.  *
  681.  * Fsrmt_Select --
  682.  *
  683.  *    Select on a remote file/device/pipe.  This does an RPC to the
  684.  *    I/O server which invokes a stream-specific select routine.
  685.  *
  686.  * Results:
  687.  *    A return status.
  688.  *
  689.  * Side effects:
  690.  *    None.
  691.  *
  692.  *----------------------------------------------------------------------
  693.  */
  694. ReturnStatus
  695. Fsrmt_Select(hdrPtr, waitPtr, readPtr, writePtr, exceptPtr)
  696.     Fs_HandleHeader    *hdrPtr;    /* Handle from stream to select */
  697.     Sync_RemoteWaiter    *waitPtr;    /* Information for remote waiting. */
  698.     int              *readPtr;    /* In/Out read ability */
  699.     int              *writePtr;    /* In/Out write ability */
  700.     int              *exceptPtr;    /* In/Out exception ability */
  701. {
  702.     ReturnStatus         status;
  703.     Rpc_Storage         storage;
  704.     FsRemoteSelectParams    selectParams;
  705.     FsRemoteSelectResults    selectResults;
  706.  
  707.     FSRMT_RPC_DEBUG_PRINT("Fsrmt_Select: Selecting file\n");
  708.  
  709.     selectParams.fileID = hdrPtr->fileID;
  710.     selectParams.read = *readPtr;
  711.     selectParams.write = *writePtr;
  712.     selectParams.except = *exceptPtr;
  713.     if (waitPtr == (Sync_RemoteWaiter *)NIL) {
  714.     /*
  715.      * Indicate a polling select with a NIL hostID.
  716.      */
  717.     selectParams.waiter.hostID = NIL;
  718.     } else {
  719.     selectParams.waiter = *waitPtr;
  720.     }
  721.  
  722.     storage.requestParamPtr = (Address)&selectParams;
  723.     storage.requestParamSize = sizeof(selectParams);
  724.     storage.requestDataPtr = (Address)NIL;
  725.     storage.requestDataSize = 0;
  726.  
  727.     storage.replyParamPtr = (Address) &selectResults;
  728.     storage.replyParamSize = sizeof(FsRemoteSelectResults);
  729.     storage.replyDataPtr = (Address) NIL;
  730.     storage.replyDataSize = 0;
  731.  
  732.     status = Rpc_Call(hdrPtr->fileID.serverID, RPC_FS_SELECT, &storage);
  733.     if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  734.     status == RPC_SERVICE_DISABLED) {
  735.     /*
  736.      * Mask the error and leave the bits set in the request masks.
  737.      * This will cause the application to try a read or write
  738.      * of this stream and then it will learn something is amiss.
  739.      */
  740.     Fsutil_WantRecovery(hdrPtr);
  741.     status = SUCCESS;
  742.     } else {
  743.     *readPtr = selectResults.read;
  744.     *writePtr = selectResults.write;
  745.     *exceptPtr = selectResults.except;
  746.     }
  747.  
  748.     return(status);
  749. }
  750.  
  751. /*
  752.  *----------------------------------------------------------------------
  753.  *
  754.  * Fsrmt_RpcSelectStub --
  755.  *
  756.  *    The service stub for RPC_FS_SELECT.
  757.  *
  758.  * Results:
  759.  *    If this procedure returns SUCCESS then a reply has been sent to
  760.  *    the client.  If the arguments are bad then FS_STALE_HANDLE is 
  761.  *    returned and the main level sends back an error reply.
  762.  *
  763.  * Side effects:
  764.  *    Calls the domain-level select routine to attempt the lock operation.
  765.  *
  766.  *----------------------------------------------------------------------
  767.  */
  768. /*ARGSUSED*/
  769. ReturnStatus
  770. Fsrmt_RpcSelectStub(srvToken, clientID, command, storagePtr)
  771.     ClientData srvToken;    /* Handle on server process passed to
  772.                  * Rpc_Reply */
  773.     int clientID;        /* Sprite ID of client host */
  774.     int command;        /* Command identifier */
  775.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  776.                  * buffers and also indicate the exact amount
  777.                  * of data in the request buffers.  The reply
  778.                  * fields are initialized to NIL for the
  779.                  * pointers and 0 for the lengths.  This can
  780.                  * be passed to Rpc_Reply */
  781. {
  782.     register    FsRemoteSelectParams    *paramsPtr;
  783.     register    FsRemoteSelectResults    *resultsPtr;
  784.     register    Fs_HandleHeader        *hdrPtr;
  785.     register    Rpc_ReplyMem        *replyMemPtr;
  786.     register    Sync_RemoteWaiter    *waitPtr;
  787.     ReturnStatus            status;
  788.  
  789.     FSRMT_RPC_DEBUG_PRINT("RPC select request\n");
  790.  
  791.     paramsPtr = (FsRemoteSelectParams *)storagePtr->requestParamPtr;
  792.  
  793.     hdrPtr = (*fsio_StreamOpTable[paramsPtr->fileID.type].clientVerify)
  794.     (¶msPtr->fileID, clientID, (int *)NIL);
  795.     if (hdrPtr == (Fs_HandleHeader *) NIL) {
  796.     return(FS_STALE_HANDLE);
  797.     }
  798.     Fsutil_HandleUnlock(hdrPtr);
  799.     if (paramsPtr->waiter.hostID == NIL) {
  800.     /*
  801.      * Indicate a polling select.
  802.      */
  803.     waitPtr = (Sync_RemoteWaiter *)NIL;
  804.     } else {
  805.     waitPtr = ¶msPtr->waiter;
  806.     }
  807.     status = (*fsio_StreamOpTable[paramsPtr->fileID.type].select)
  808.     (hdrPtr, waitPtr, ¶msPtr->read,
  809.      ¶msPtr->write, ¶msPtr->except);
  810.     Fsutil_HandleRelease(hdrPtr, FALSE);
  811.     if (status == SUCCESS) {
  812.     resultsPtr = mnew(FsRemoteSelectResults);
  813.     resultsPtr->read = paramsPtr->read;
  814.     resultsPtr->write = paramsPtr->write;
  815.     resultsPtr->except = paramsPtr->except;
  816.     storagePtr->replyParamPtr = (Address) resultsPtr;
  817.     storagePtr->replyParamSize = sizeof(FsRemoteSelectResults);
  818.     replyMemPtr = (Rpc_ReplyMem *) malloc(sizeof(Rpc_ReplyMem));
  819.     replyMemPtr->paramPtr = (Address) resultsPtr;
  820.     replyMemPtr->dataPtr = (Address) NIL;
  821.     Rpc_Reply(srvToken, SUCCESS, storagePtr, 
  822.           (int (*)()) Rpc_FreeMem, (ClientData) replyMemPtr);
  823.     } else {
  824.     Rpc_Reply(srvToken, status, storagePtr, 
  825.           (int (*)())NIL, (ClientData)NIL);
  826.     }
  827.  
  828.     return(SUCCESS);
  829. }
  830.  
  831. /*
  832.  *----------------------------------------------------------------------
  833.  *
  834.  * Fsrmt_IOControl --
  835.  *
  836.  *    Client stub for RPC_FS_IOCONTROL.
  837.  *    Do a special operation on a remote Sprite file/device/pipe/etc.
  838.  *
  839.  * Results:
  840.  *    None.
  841.  *
  842.  * Side effects:
  843.  *    None.
  844.  *
  845.  *----------------------------------------------------------------------
  846.  */
  847. ReturnStatus
  848. Fsrmt_IOControl(streamPtr, ioctlPtr, replyPtr)
  849.     Fs_Stream    *streamPtr;
  850.     Fs_IOCParam *ioctlPtr;        /* I/O Control parameter block */
  851.     Fs_IOReply *replyPtr;        /* Return length and signal */
  852. {
  853.     register Fs_HandleHeader    *hdrPtr = streamPtr->ioHandlePtr;
  854.     FsrmtIOCParam        params;
  855.     ReturnStatus        status;
  856.     Rpc_Storage            storage;
  857.  
  858.     FSRMT_RPC_DEBUG_PRINT("Fsrmt_IOControl\n");
  859.  
  860.     params.fileID = hdrPtr->fileID;
  861.     params.streamID = streamPtr->hdr.fileID;
  862.     params.procID = ioctlPtr->procID;
  863.     params.familyID = ioctlPtr->familyID;
  864.     params.command = ioctlPtr->command;
  865.     params.inBufSize = ioctlPtr->inBufSize;
  866.     params.outBufSize = ioctlPtr->outBufSize;
  867.     params.format = ioctlPtr->format;
  868.     params.uid = ioctlPtr->uid;
  869.  
  870.     storage.requestParamPtr = (Address)¶ms;
  871.     storage.requestParamSize = sizeof(FsrmtIOCParam);
  872.     storage.requestDataPtr = (Address) ioctlPtr->inBuffer;
  873.     storage.requestDataSize = ioctlPtr->inBufSize;
  874.     storage.replyParamPtr = (Address)replyPtr;
  875.     storage.replyParamSize = sizeof(Fs_IOReply);
  876.     storage.replyDataPtr = (Address)ioctlPtr->outBuffer;
  877.     storage.replyDataSize = ioctlPtr->outBufSize;
  878.  
  879.     status = Rpc_Call(hdrPtr->fileID.serverID, RPC_FS_IO_CONTROL, &storage);
  880.     if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  881.     status == RPC_SERVICE_DISABLED) {
  882.     Fsutil_WantRecovery(hdrPtr);
  883.     }
  884.  
  885.     return(status);
  886. }
  887.  
  888. /*
  889.  *----------------------------------------------------------------------
  890.  *
  891.  * Fsrmt_RpcIOControl --
  892.  *
  893.  *    Service stub for RPC_FS_IOCONTROL.
  894.  *
  895.  * Results:
  896.  *    If this procedure returns SUCCESS then a reply has been sent to
  897.  *    the client.  If the arguments are bad then FS_STALE_HANDLE is 
  898.  *    returned and the main level sends back an error reply.
  899.  *
  900.  * Side effects:
  901.  *    Calls the local io control routine.
  902.  *
  903.  *----------------------------------------------------------------------
  904.  */
  905. /*ARGSUSED*/
  906. ReturnStatus
  907. Fsrmt_RpcIOControl(srvToken, clientID, command, storagePtr)
  908.     ClientData srvToken;    /* Handle on server process passed to
  909.                  * Rpc_Reply */
  910.     int clientID;        /* Sprite ID of client host */
  911.     int command;        /* IGNORED */
  912.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  913.                  * buffers and also indicate the exact amount
  914.                  * of data in the request buffers.  The reply
  915.                  * fields are initialized to NIL for the
  916.                  * pointers and 0 for the lengths.  This can
  917.                  * be passed to Rpc_Reply */
  918. {
  919.     register    FsrmtIOCParam    *paramsPtr;
  920.     register    Fs_HandleHeader        *hdrPtr;
  921.     register    Fs_Stream        *streamPtr;
  922.     register    Rpc_ReplyMem        *replyMemPtr;
  923.     ReturnStatus            status = SUCCESS;
  924.     Address                outBufPtr;
  925.     Fs_IOCParam                ioctl;
  926.     Fs_IOReply                *replyPtr;
  927.  
  928.     paramsPtr = (FsrmtIOCParam *)storagePtr->requestParamPtr;
  929.  
  930.     hdrPtr = (*fsio_StreamOpTable[paramsPtr->fileID.type].clientVerify)
  931.         (¶msPtr->fileID, clientID, (int *)NIL);
  932.     if (hdrPtr == (Fs_HandleHeader *)NIL) {
  933.     printf("Fsrmt_RpcIOControl, no handle <%d,%d> client %d\n",
  934.         paramsPtr->fileID.major, paramsPtr->fileID.minor, clientID);
  935.     return(FS_STALE_HANDLE);
  936.     }
  937.     streamPtr = Fsio_StreamClientVerify(¶msPtr->streamID, hdrPtr, clientID);
  938.     if (streamPtr == (Fs_Stream *)NIL) {
  939.     printf("Fsrmt_RpcIOControl no stream <%d> to handle <%d,%d> client %d\n",
  940.         paramsPtr->streamID.minor,
  941.         paramsPtr->fileID.major, paramsPtr->fileID.minor,
  942.         clientID);
  943.     Fsutil_HandleRelease(hdrPtr, TRUE);
  944.     return( (paramsPtr->streamID.minor < 0) ? GEN_INVALID_ARG
  945.                         : FS_STALE_HANDLE );
  946.     }
  947.     Fsutil_HandleUnlock(hdrPtr);
  948.  
  949.     if (paramsPtr->outBufSize != 0) {
  950.     outBufPtr = (Address)malloc(paramsPtr->outBufSize);
  951.     } else {
  952.     outBufPtr = (Address)NIL;
  953.     }
  954.     ioctl.command = paramsPtr->command;
  955.     ioctl.inBuffer = storagePtr->requestDataPtr;
  956.     ioctl.inBufSize = paramsPtr->inBufSize;
  957.     ioctl.outBuffer = outBufPtr;
  958.     ioctl.outBufSize = paramsPtr->outBufSize;
  959.     ioctl.flags = 0;    /* All buffers in kernel space */
  960.     ioctl.format = paramsPtr->format;
  961.     ioctl.procID = paramsPtr->procID;
  962.     ioctl.familyID = paramsPtr->familyID;
  963.     ioctl.uid = paramsPtr->uid;
  964.  
  965.     replyPtr = mnew(Fs_IOReply);
  966.     replyPtr->length = paramsPtr->outBufSize;
  967.     replyPtr->flags = 0;
  968.     replyPtr->signal = 0;
  969.     replyPtr->code = 0;
  970.  
  971.     /*
  972.      * Update server's shadow stream offset for IOC_REPOSITION
  973.      */
  974.     if (ioctl.command == IOC_REPOSITION) {
  975.     int newOffset = -1;
  976.     register Ioc_RepositionArgs *iocArgsPtr = (Ioc_RepositionArgs *) NIL;
  977.     Ioc_RepositionArgs    iocArgs;
  978.     int size;
  979.     int inSize;
  980.  
  981.     if ((ioctl.inBuffer == (Address)NIL) || 
  982.         (ioctl.inBufSize < sizeof(Ioc_RepositionArgs))) {
  983.         status = GEN_INVALID_ARG;
  984.     } else if (ioctl.format != mach_Format) {
  985.         int fmtStatus;
  986.         size = sizeof(Ioc_RepositionArgs);
  987.         inSize = ioctl.inBufSize;
  988.         fmtStatus = Fmt_Convert("ww", ioctl.format, &inSize,
  989.                 ioctl.inBuffer, mach_Format, &size,
  990.                 (Address) &iocArgs);
  991.         if (fmtStatus != 0) {
  992.         printf("Format of ioctl failed <0x%x>\n", fmtStatus);
  993.         status = GEN_INVALID_ARG;
  994.         }
  995.         if (size != sizeof(Ioc_RepositionArgs)) {
  996.         status = GEN_INVALID_ARG;
  997.         }
  998.         iocArgsPtr = &iocArgs;
  999.     } else {
  1000.         iocArgsPtr = (Ioc_RepositionArgs *)ioctl.inBuffer;
  1001.     }
  1002.     if (status == SUCCESS) {
  1003.         switch(iocArgsPtr->base) {
  1004.         case IOC_BASE_ZERO:
  1005.             newOffset = iocArgsPtr->offset;
  1006.             break;
  1007.         case IOC_BASE_CURRENT:
  1008.             newOffset = streamPtr->offset + iocArgsPtr->offset;
  1009.             break;
  1010.         case IOC_BASE_EOF: {
  1011.             Fs_Attributes attrs;
  1012.     
  1013.             status = Fs_GetAttrStream(streamPtr, &attrs);
  1014.             if (status != SUCCESS) {
  1015.             break;
  1016.             }
  1017.             if (streamPtr->nameInfoPtr != (Fs_NameInfo *) NIL) {
  1018.             size = attrs.size;
  1019.             }
  1020.             newOffset = size + iocArgsPtr->offset;
  1021.             break;
  1022.         }
  1023.         }
  1024.         if (newOffset < 0) {
  1025.         status = GEN_INVALID_ARG;
  1026.         } else {
  1027.         if (ioctl.outBufSize >= sizeof(int) &&
  1028.             ioctl.outBuffer == (Address) NIL) {
  1029.             if (ioctl.format != mach_Format) {
  1030.             int size = sizeof(int);
  1031.             int inSize = sizeof(int);
  1032.             int fmtStatus;
  1033.             fmtStatus = Fmt_Convert("w", mach_Format, &inSize,
  1034.                         (Address) &newOffset,
  1035.                         ioctl.format, 
  1036.                         &size,
  1037.                         (Address) ioctl.outBuffer);
  1038.             if (fmtStatus != 0) {
  1039.                 printf("Format of ioctl failed <0x%x>\n",
  1040.                    fmtStatus);
  1041.                 status = GEN_INVALID_ARG;
  1042.             }
  1043.             if (size != sizeof(int)) {
  1044.                 status = GEN_INVALID_ARG;
  1045.             }
  1046.             } else {
  1047.             *(int *)ioctl.outBuffer = newOffset;
  1048.             }
  1049.         }
  1050.         if (status == SUCCESS) {
  1051.             streamPtr->offset = newOffset;
  1052.         }
  1053.         }
  1054.     }
  1055.     }
  1056.     Fsutil_HandleRelease(streamPtr, TRUE);
  1057.     if (status == SUCCESS) {
  1058.     status = (*fsio_StreamOpTable[hdrPtr->fileID.type].ioControl)(streamPtr,
  1059.             &ioctl, replyPtr);
  1060. #ifdef lint
  1061.     status = Fsio_FileIOControl(streamPtr, &ioctl, replyPtr);
  1062.     status = Fsio_PipeIOControl(streamPtr, &ioctl, replyPtr);
  1063.     status = Fsio_DeviceIOControl(streamPtr, &ioctl, replyPtr);
  1064.     status = FspdevPseudoStreamIOControl(streamPtr, &ioctl, replyPtr);
  1065. #endif /* lint */
  1066.     }
  1067.     Fsutil_HandleRelease(hdrPtr, FALSE);
  1068.  
  1069.     FSRMT_RPC_DEBUG_PRINT1("Fsrmt_RpcIOControl returns <%x>\n", status);
  1070.  
  1071.     if ((replyPtr->length == 0) && (outBufPtr != (Address)NIL)) {
  1072.     free((Address) outBufPtr);
  1073.     outBufPtr = (Address)NIL;
  1074.     }
  1075.     storagePtr->replyDataPtr = outBufPtr;
  1076.     storagePtr->replyDataSize = replyPtr->length;
  1077.     storagePtr->replyParamPtr = (Address)replyPtr;
  1078.     storagePtr->replyParamSize = sizeof(Fs_IOReply);
  1079.  
  1080.     replyMemPtr = (Rpc_ReplyMem *) malloc(sizeof(Rpc_ReplyMem));
  1081.     replyMemPtr->paramPtr = (Address)replyPtr;
  1082.     replyMemPtr->dataPtr = outBufPtr;
  1083.     Rpc_Reply(srvToken, status, storagePtr, 
  1084.           (int (*)()) Rpc_FreeMem, (ClientData) replyMemPtr);
  1085.  
  1086.     return(SUCCESS);
  1087. }
  1088.  
  1089. /*
  1090.  *----------------------------------------------------------------------
  1091.  *
  1092.  * Fsrmt_BlockCopy --
  1093.  *
  1094.  *    Copy the file system block from the source to the destination file.
  1095.  *    This only works for remote file handles as this is only used
  1096.  *    on remote swap files.
  1097.  *
  1098.  * Results:
  1099.  *    Return status from the rpc to the server.
  1100.  *
  1101.  * Side effects:
  1102.  *    The RPC does the block copy on the server.
  1103.  *
  1104.  *----------------------------------------------------------------------
  1105.  */
  1106.  
  1107. ReturnStatus
  1108. Fsrmt_BlockCopy(srcHdrPtr, dstHdrPtr, blockNum)
  1109.     Fs_HandleHeader    *srcHdrPtr;    /* Source file handle. */
  1110.     Fs_HandleHeader    *dstHdrPtr;    /* Dest file handle. */
  1111.     int            blockNum;    /* Block to copy. */
  1112. {
  1113.     ReturnStatus         status;
  1114.     FsrmtBlockCopyParam    params;
  1115.     Rpc_Storage         storage;
  1116.     Fsrmt_FileIOHandle        *srcHandlePtr;
  1117.     Fsrmt_FileIOHandle        *dstHandlePtr;
  1118.  
  1119.     if (srcHdrPtr->fileID.type != FSIO_RMT_FILE_STREAM) {
  1120.     panic( "Fsrmt_BlockCopy, bad stream type <%d>\n",
  1121.         srcHdrPtr->fileID.type);
  1122.     srcHandlePtr = (Fsrmt_FileIOHandle *) NIL;
  1123.     dstHandlePtr = (Fsrmt_FileIOHandle *) NIL;
  1124.     return(FAILURE);
  1125.     } else {
  1126.     srcHandlePtr = (Fsrmt_FileIOHandle *)srcHdrPtr;
  1127.     dstHandlePtr = (Fsrmt_FileIOHandle *)dstHdrPtr;
  1128.     }
  1129.  
  1130.     params.srcFileID = srcHdrPtr->fileID;
  1131.     params.destFileID = dstHdrPtr->fileID;
  1132.     params.blockNum = blockNum;
  1133.     storage.requestParamPtr = (Address)¶ms;
  1134.     storage.requestParamSize = sizeof(FsrmtBlockCopyParam);
  1135.     storage.requestDataPtr = (Address)NIL;
  1136.     storage.requestDataSize = 0;
  1137.     storage.replyParamPtr = (Address)NIL;
  1138.     storage.replyParamSize = 0;
  1139.     storage.replyDataPtr = (Address)NIL;
  1140.     storage.replyDataSize = 0;
  1141.  
  1142.     status = Rpc_Call(srcHdrPtr->fileID.serverID, RPC_FS_COPY_BLOCK, &storage);
  1143.     if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  1144.     status == RPC_SERVICE_DISABLED) {
  1145.     Fsutil_WantRecovery((Fs_HandleHeader *)srcHandlePtr);
  1146.     Fsutil_WantRecovery((Fs_HandleHeader *)dstHandlePtr);
  1147.     }
  1148.     return(status);
  1149. }
  1150.  
  1151.  
  1152. /*
  1153.  *----------------------------------------------------------------------
  1154.  *
  1155.  * Fsrmt_RpcBlockCopy --
  1156.  *
  1157.  *    Service stub for Fsrmt_BlockCopy.
  1158.  *
  1159.  * Results:
  1160.  *    If this procedure returns SUCCESS then a reply has been sent to
  1161.  *    the client.  If the arguments are bad then FS_STALE_HANDLE is 
  1162.  *    returned and the main level sends back an error reply.
  1163.  *
  1164.  * Side effects:
  1165.  *    Calls the local io control routine.
  1166.  *
  1167.  *----------------------------------------------------------------------
  1168.  */
  1169. /*ARGSUSED*/
  1170. ReturnStatus
  1171. Fsrmt_RpcBlockCopy(srvToken, clientID, command, storagePtr)
  1172.     ClientData srvToken;    /* Handle on server process passed to
  1173.                  * Rpc_Reply */
  1174.     int clientID;        /* Sprite ID of client host */
  1175.     int command;        /* IGNORED */
  1176.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  1177.                  * buffers and also indicate the exact amount
  1178.                  * of data in the request buffers.  The reply
  1179.                  * fields are initialized to NIL for the
  1180.                  * pointers and 0 for the lengths.  This can
  1181.                  * be passed to Rpc_Reply */
  1182. {
  1183.     register    FsrmtBlockCopyParam    *paramsPtr;
  1184.     register    Fs_HandleHeader        *srcHdrPtr;
  1185.     register    Fs_HandleHeader        *dstHdrPtr;
  1186.     ReturnStatus            status;
  1187.  
  1188.     FSRMT_RPC_DEBUG_PRINT("RPC block copy request\n");
  1189.  
  1190.     paramsPtr = (FsrmtBlockCopyParam *)storagePtr->requestParamPtr;
  1191.  
  1192.     /*
  1193.      * Fetch the source and dest handles.  We know that they won't go away
  1194.      * while we are using them because of the way swap files are handled.
  1195.      */
  1196.     dstHdrPtr = (*fsio_StreamOpTable[paramsPtr->destFileID.type].clientVerify)
  1197.         (¶msPtr->destFileID, clientID, (int *)NIL);
  1198.     if (dstHdrPtr == (Fs_HandleHeader *)NIL) {
  1199.     return(FS_STALE_HANDLE);
  1200.     }
  1201.     Fsutil_HandleRelease(dstHdrPtr, TRUE);
  1202.  
  1203.     srcHdrPtr = (*fsio_StreamOpTable[paramsPtr->srcFileID.type].clientVerify)
  1204.         (¶msPtr->srcFileID, clientID, (int *)NIL);
  1205.     if (srcHdrPtr == (Fs_HandleHeader *)NIL) {
  1206.     return(FS_STALE_HANDLE);
  1207.     }
  1208.  
  1209.     status = (*fsio_StreamOpTable[paramsPtr->srcFileID.type].blockCopy)
  1210.                 (srcHdrPtr, dstHdrPtr, paramsPtr->blockNum);
  1211.     Fsutil_HandleRelease(srcHdrPtr, TRUE);
  1212.  
  1213.     Rpc_Reply(srvToken, status, storagePtr, (int (*)())NIL, (ClientData)NIL);
  1214.     return(SUCCESS);
  1215. }
  1216.  
  1217. /*
  1218.  * The return values from the RPC_FS_DOMAIN_INFO call.
  1219.  * (The inputs are a fileID.)
  1220.  */
  1221. typedef struct FsDomainInfoResults {
  1222.     Fs_DomainInfo    domain;
  1223.     Fs_FileID        fileID;
  1224. } FsDomainInfoResults;
  1225. /*
  1226.  *----------------------------------------------------------------------
  1227.  *
  1228.  * Fsrmt_DomainInfo --
  1229.  *
  1230.  *    Return information about the given domain.
  1231.  *
  1232.  * Results:
  1233.  *    None.
  1234.  *
  1235.  * Side effects:
  1236.  *    None.
  1237.  *
  1238.  *----------------------------------------------------------------------
  1239.  */
  1240. ReturnStatus
  1241. Fsrmt_DomainInfo(fileIDPtr, domainInfoPtr)
  1242.     Fs_FileID        *fileIDPtr;
  1243.     Fs_DomainInfo    *domainInfoPtr;    
  1244. {
  1245.     register ReturnStatus    status;
  1246.     FsDomainInfoResults        results;
  1247.     Rpc_Storage            storage;
  1248.  
  1249. #ifdef notdef
  1250. retry:
  1251. #endif
  1252.     storage.requestParamPtr = (Address)fileIDPtr;
  1253.     storage.requestParamSize = sizeof(Fs_FileID);
  1254.     storage.requestDataPtr = (Address) NIL;
  1255.     storage.requestDataSize = 0;
  1256.     storage.replyParamPtr = (Address)&results;
  1257.     storage.replyParamSize = sizeof(FsDomainInfoResults);
  1258.     storage.replyDataPtr = (Address) NIL;
  1259.     storage.replyDataSize = 0;
  1260.  
  1261.     status = Rpc_Call(fileIDPtr->serverID, RPC_FS_DOMAIN_INFO, &storage);
  1262.  
  1263.     if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  1264.     status == RPC_SERVICE_DISABLED) {
  1265.     /*
  1266.      * Wait for recovery here, instead of higher up in Fsutil_DomainInfo.
  1267.      * This is because the server-side stub can't check against
  1268.      * stale handle conditions, so it always calls Fsutil_DomainInfo.
  1269.      * We don't want to ever wait for recovery on the server,
  1270.      * so we do it here where we know we are a client.
  1271.      */
  1272.     Fs_HandleHeader *hdrPtr;
  1273.     hdrPtr = Fsutil_HandleFetch(fileIDPtr);
  1274.     if (hdrPtr == (Fs_HandleHeader *)NIL) {
  1275.         printf("Fsrmt_DomainInfo: Can't fetch <%d,%d,%d,%d>\n",
  1276.             fileIDPtr->type, fileIDPtr->serverID,
  1277.             fileIDPtr->major, fileIDPtr->minor);
  1278.     } else {
  1279.         Fsutil_HandleUnlock(hdrPtr);
  1280.         Fsutil_WantRecovery(hdrPtr);
  1281. #ifdef notdef
  1282.         /*
  1283.          * We don't wait for recovery because that hangs getwd(),
  1284.          * which in turn hangs shell scripts.  We have marked the
  1285.          * handle as needing recovery, however, so recovery will
  1286.          * happen eventually.
  1287.          */
  1288.         printf("Fsrmt_DomainInfo: waiting for recovery <%d,%d> server %d\n",
  1289.             fileIDPtr->major, fileIDPtr->minor, fileIDPtr->serverID);
  1290.         status = Fsutil_WaitForRecovery(hdrPtr, status);
  1291.         if (status == SUCCESS) {
  1292.         goto retry;
  1293.         }
  1294. #endif
  1295.     }
  1296.     }
  1297.     if (status == SUCCESS) {
  1298.     *domainInfoPtr = results.domain;
  1299.     *fileIDPtr = results.fileID;
  1300.     }
  1301.  
  1302.     return(status);
  1303. }
  1304.  
  1305. /*
  1306.  *----------------------------------------------------------------------
  1307.  *
  1308.  * Fsrmt_RpcDomainInfo --
  1309.  *
  1310.  *    Service stub for RPC_FS_DOMAIN_INFO.
  1311.  *
  1312.  * Results:
  1313.  *    If this procedure returns SUCCESS then a reply has been sent to
  1314.  *    the client.  If the arguments are bad then FS_DOMAIN_UNAVAILABLE is
  1315.  *    returned and the main level sends back an error reply.
  1316.  *
  1317.  * Side effects:
  1318.  *    Calls the top-level Fsutil_DomainInfo routine to get information
  1319.  *    about the domain.
  1320.  *
  1321.  *----------------------------------------------------------------------
  1322.  */
  1323. /*ARGSUSED*/
  1324. ReturnStatus
  1325. Fsrmt_RpcDomainInfo(srvToken, clientID, command, storagePtr)
  1326.     ClientData srvToken;    /* Handle on server process passed to
  1327.                  * Rpc_Reply */
  1328.     int clientID;        /* IGNORED */
  1329.     int command;        /* IGNORED */
  1330.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  1331.                  * buffers and also indicate the exact amount
  1332.                  * of data in the request buffers.  The reply
  1333.                  * fields are initialized to NIL for the
  1334.                  * pointers and 0 for the lengths.  This can
  1335.                  * be passed to Rpc_Reply */
  1336. {
  1337.     ReturnStatus    status;
  1338.     Fs_FileID        *fileIDPtr;
  1339.     FsDomainInfoResults    *resultsPtr;
  1340.     Rpc_ReplyMem    *replyMemPtr;
  1341.  
  1342.     fileIDPtr = (Fs_FileID *)storagePtr->requestParamPtr;
  1343.     resultsPtr = mnew(FsDomainInfoResults);
  1344.     fileIDPtr->type = Fsio_MapRmtToLclType(fileIDPtr->type);
  1345.     resultsPtr->fileID = *fileIDPtr;
  1346.  
  1347.     status = Fsutil_DomainInfo(&resultsPtr->fileID, &resultsPtr->domain);
  1348.  
  1349.     storagePtr->replyParamPtr = (Address) resultsPtr;
  1350.     storagePtr->replyParamSize = sizeof(FsDomainInfoResults);
  1351.     replyMemPtr = (Rpc_ReplyMem *) malloc(sizeof(Rpc_ReplyMem));
  1352.     replyMemPtr->paramPtr = (Address) resultsPtr;
  1353.     replyMemPtr->dataPtr = (Address) NIL;
  1354.     Rpc_Reply(srvToken, status, storagePtr, 
  1355.           (int (*)()) Rpc_FreeMem, (ClientData) replyMemPtr);
  1356.  
  1357.     return(SUCCESS);    /* Because we've already replied */
  1358. }
  1359.